﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace comm
{
    #region Dots
    public class Dots
    {
        List<int[]> _dots = new List<int[]>();

        bool Exists(int x, int y)
        {
            return _dots.Exists(arr =>
            {
                return arr[0] == x && arr[1] == y;
            });
        }

        public void Add(int x, int y, int w, int h, bool fz = false)
        {
            var list = new List<int[]>();
            for (int x1 = 0; x1 < w; x1++)
            {
                for (int y1 = 0; y1 < h; y1++)
                {
                    if (!Exists(x + x1, y + y1))
                    {
                        list.Add(new int[] { x + x1, y + y1 });
                    }
                }
            }
            if (fz)
            {
                list.Reverse();
            }
            _dots.AddRange(list);
        }
        public void AddRange(int[][] dots)
        {
            foreach (var dot in dots)
            {
                if (!Exists(dot[0], dot[1]))
                {
                    _dots.Add(dot);
                }
            }
        }
        public int[][] ToArray()
        {
            return _dots.ToArray();
        }
    }
    #endregion

    public static class MathHelper
    {
        static Dictionary<objst.DirType, int[][]> _dirRadianDic = new Dictionary<objst.DirType, int[][]>();
        static MathHelper()
        {
            var range = 8;
            var rc = 360 / range;
            for (int i = 0; i < range; i++)
            {
                var ra = rc * i;
                var start = ra - rc / 2;
                var end = ra + rc / 2;
                var dir = (objst.DirType)i;
                _dirRadianDic.Add(dir, new int[][] { new int[] { ra }, new int[] { start, end } });
            }
        }

        static void MakeOvQds(Dots dots, int cx, int cy, int x, int y, int w, int h, int wod, int hod)
        {
            var xl = cx - x;
            var xr = cx + x + wod - w;
            var yt = cy - y;
            var yb = cy + y + hod - h;
            if (xr > xl + w)
            {
                dots.Add(xr, yt, w, h);
                dots.Add(xr, yb, w, h);
            }
            else
            {
                w = xr - xl + w;
            }
            dots.Add(xl, yt, w, h);
            dots.Add(xl, yb, w, h);
        }
        static void MakeArcDots(Dots dots, int x, int y, int oy, int cx, int cy, int iOdds, int[] aBndA, int[] aBndZ, int iSects)
        {
            var xrDef = cx + x + (iOdds & 0xffff);
            var y2 = 0;
            var h = oy - y;
            var xl = 0;
            var xr = 0;
            var w = 0;

            if (h == 0)
            {
                h = 1;
            }
            x = cx - x;

            if ((iSects & 0xff0000) != 0) // Start-angle > end-angle
            {
                y2 = cy - y - h;
                if ((iSects & 0x00ff) != 0)
                {
                    if ((iSects & 0x02) != 0)
                    {
                        xl = Math.Max(x, aBndZ[y]);
                        w = xrDef - xl;
                        if (w > 0)
                        {
                            dots.Add(xl, y2, w, h);
                        }
                    }
                    if ((iSects & 0x01) != 0)
                    {
                        xr = Math.Min(xrDef, aBndA[y]);
                        w = xr - x;
                        if (w > 0)
                        {
                            dots.Add(x, y2, w, h);
                        }
                    }
                }
                else
                {
                    dots.Add(x, y2, xrDef - x, h);
                }
                y2 = cy + y + (iOdds >> 16);
                if ((iSects & 0xff00) != 0)
                {
                    if ((iSects & 0x0100) != 0)
                    {
                        xl = Math.Max(x, aBndA[y]);
                        w = xrDef - xl;
                        if (w > 0)
                        {
                            dots.Add(xl, y2, w, h);
                        }
                    }
                    if ((iSects & 0x0200) != 0)
                    {
                        xr = Math.Min(xrDef, aBndZ[y]);
                        w = xr - x;
                        if (w > 0)
                        {
                            dots.Add(x, y2, w, h);
                        }
                    }
                }
                else
                {
                    dots.Add(x, y2, xrDef - x, h);
                }
            }
            else
            {
                if ((iSects & 0x00ff) != 0)
                {
                    if ((iSects & 0x02) != 0)
                    {
                        xl = Math.Max(x, aBndZ[y]);
                    }
                    else
                    {
                        xl = x;
                    }
                    if ((iSects & 0x01) != 0)
                    {
                        xr = Math.Min(xrDef, aBndA[y]);
                    }
                    else
                    {
                        xr = xrDef;
                    }
                    y2 = cy - y - h;
                    w = xr - xl;
                    if (w > 0)
                    {
                        dots.Add(xl, y2, w, h);
                    }
                }
                if ((iSects & 0xff00) != 0)
                {
                    if ((iSects & 0x0100) != 0)
                    {
                        xl = Math.Max(x, aBndA[y]);
                    }
                    else
                    {
                        xl = x;
                    }
                    if ((iSects & 0x0200) != 0)
                    {
                        xr = Math.Min(xrDef, aBndZ[y]);
                    }
                    else
                    {
                        xr = xrDef;
                    }
                    y2 = cy + y + (iOdds >> 16);
                    w = xr - xl;
                    if (w > 0)
                    {
                        dots.Add(xl, y2, w, h);
                    }
                }
            }
        }
        static void MakeLinVirt(int[] aLin, int x1, int y1, int x2, int y2)
        {
            var dx = Math.Abs(x2 - x1);
            var dy = Math.Abs(y2 - y1);
            var x = x1;
            var y = y1;
            var xIncr = (x1 > x2) ? -1 : 1;
            var yIncr = (y1 > y2) ? -1 : 1;
            var p = 0;
            var i = 0;
            if (dx >= dy)
            {
                var pr = dy << 1;
                var pru = pr - (dx << 1);
                p = pr - dx;
                while (dx > 0)
                {
                    --dx;
                    if (p > 0)    //  Increment y
                    {
                        aLin[i++] = x;
                        y += yIncr;
                        p += pru;
                    }
                    else
                    {
                        p += pr;
                    }
                    x += xIncr;
                }
            }
            else
            {
                var pr = dx << 1;
                var pru = pr - (dy << 1);
                p = pr - dy;
                while (dy > 0)
                {
                    --dy;
                    y += yIncr;
                    aLin[i++] = x;
                    if (p > 0)    //  Increment x
                    {
                        x += xIncr;
                        p += pru;
                    }
                    else
                    {
                        p += pr;
                    }
                }
            }

            //for (var len = aLin.length, i = len - i; i; )
            //    aLin[len - (i--)] = x;

            var len = aLin.Length;
            for (i = len - i; i > 0; )
            {
                aLin[len - (i--)] = x;
            }
        }

        static Random _random = new Random();
        public static int RandomInt(int min, int max)
        {
            lock (_random)
            {
                return _random.Next(min, max);
            }
        }
        public static double RandomDouble()
        {
            lock (_random)
            {
                return _random.NextDouble();
            }
        }

        public static double PointDistance(int sx, int sy, int ex, int ey)
        {
            int x = Math.Abs(ex - sx);
            int y = Math.Abs(ey - sy);
            return Math.Sqrt(x * x + y * y);
        }
        public static double PointAngle(int x1, int y1, int x2, int y2)
        {
            var dx = x2 - x1;
            var dy = y2 - y1;
            return Math.Atan2(dy, dx);
        }
        public static double PointRadian(int x1, int y1, int x2, int y2)
        {
            var r = PointAngle(x1, y1, x2, y2) * 180 / Math.PI;
            if (r > 0)
            {
                return 360 - r;
            }
            return Math.Abs(r);
        }
        public static objst.DirType PointDir(int x1, int y1, int x2, int y2)
        {
            var radian = comm.MathHelper.PointRadian(x1, y1, x2, y2);
            return comm.MathHelper.RadianToDir(radian);
        }
        public static int[][] DirToRadian(objst.DirType dir)
        {
            return _dirRadianDic[dir];
        }
        public static objst.DirType RadianToDir(double radian)
        {
            foreach (var dir in _dirRadianDic.Keys)
            {
                var arr = _dirRadianDic[dir];
                var start = arr[1][0];
                var end = arr[1][1];
                if (radian >= start && radian <= end)
                {
                    return dir;
                }
            }
            return objst.DirType.RIGHT;
        }

        //public static bool RoundIntersect(int x1, int y1, int r1, int x2, int y2, int r2)
        //{
        //    int l = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
        //    return l < (r1 + r2) * (r1 + r2);
        //}

        public static int[][] Line(int x, int y, int len, double angle)
        {
            return Line(x, y, x + (int)(Math.Cos(angle) * len), y + (int)(Math.Sin(angle) * len));
        }
        public static int[][] Line(int x1, int y1, int x2, int y2)
        {
            var dots = new Dots();
            if (x1 > x2)
            {
                var _x2 = x2;
                var _y2 = y2;
                x2 = x1;
                y2 = y1;
                x1 = _x2;
                y1 = _y2;
            }
            var dx = x2 - x1;
            var dy = Math.Abs(y2 - y1);
            var x = x1;
            var y = y1;
            var yIncr = (y1 > y2) ? -1 : 1;

            if (dx >= dy)
            {
                var pr = dy << 1;
                var pru = pr - (dx << 1);
                var p = pr - dx;
                var ox = x;
                while (dx > 0)
                {
                    --dx;
                    ++x;
                    if (p > 0)
                    {
                        dots.Add(ox, y, x - ox, 1);
                        y += yIncr;
                        p += pru;
                        ox = x;
                    }
                    else
                    {
                        p += pr;
                    }
                }
                dots.Add(ox, y, x2 - ox + 1, 1);
            }
            else
            {
                var pr = dx << 1;
                var pru = pr - (dy << 1);
                var p = pr - dy;
                var oy = y;
                if (y2 <= y1)
                {
                    while (dy > 0)
                    {
                        --dy;
                        if (p > 0)
                        {
                            dots.Add(x++, y, 1, oy - y + 1);
                            y += yIncr;
                            p += pru;
                            oy = y;
                        }
                        else
                        {
                            y += yIncr;
                            p += pr;
                        }
                    }
                    dots.Add(x2, y2, 1, oy - y2 + 1);
                }
                else
                {
                    while (dy > 0)
                    {
                        --dy;
                        y += yIncr;
                        if (p > 0)
                        {
                            dots.Add(x++, oy, 1, y - oy);
                            p += pru;
                            oy = y;
                        }
                        else p += pr;
                    }
                    dots.Add(x2, oy, 1, y2 - oy + 1);
                }
            }
            return dots.ToArray();
        }
        public static int[][] Line2D(int x1, int y1, int x2, int y2, int stroke)
        {
            var dots = new Dots();
            if (x1 > x2)
            {
                var _x2 = x2;
                var _y2 = y2;
                x2 = x1;
                y2 = y1;
                x1 = _x2;
                y1 = _y2;
            }
            var dx = x2 - x1;
            var dy = Math.Abs(y2 - y1);
            var x = x1;
            var y = y1;
            var yIncr = (y1 > y2) ? -1 : 1;

            var s = stroke;
            if (dx >= dy)
            {
                int _s = s;
                if (dx > 0 && s - 3 > 0)
                {
                    _s = (int)((s * dx * Math.Sqrt(1 + dy * dy / (dx * dx)) - dx - (s >> 1) * dy) / dx);
                    _s = (int)(!(s - 4 == 0) ? Math.Ceiling((double)_s) : Math.Round((double)_s)) + 1;
                }
                var ad = Math.Ceiling(s / 2d);

                var pr = dy << 1;
                var pru = pr - (dx << 1);
                var p = pr - dx;
                var ox = x;
                while (dx > 0)
                {
                    --dx;
                    ++x;
                    if (p > 0)
                    {
                        dots.Add(ox, y, (int)(x - ox + ad), _s);
                        y += yIncr;
                        p += pru;
                        ox = x;
                    }
                    else p += pr;
                }
                dots.Add(ox, y, (int)(x2 - ox + ad + 1), _s);
            }
            else
            {
                var _s = s;
                if (s - 3 > 0)
                {
                    _s = (int)(s * dy * Math.Sqrt(1 + dx * dx / (dy * dy)) - (s >> 1) * dx - dy) / dy;
                    _s = (int)(!(s - 4 == 0) ? (int)Math.Ceiling((double)_s) : (int)Math.Round((double)_s)) + 1;
                }
                var ad = (int)Math.Round(s / 2d);

                var pr = dx << 1;
                var pru = pr - (dy << 1);
                var p = pr - dy;
                var oy = y;
                if (y2 <= y1)
                {
                    ++ad;
                    while (dy > 0)
                    {
                        --dy;
                        if (p > 0)
                        {
                            dots.Add(x++, y, _s, oy - y + ad);
                            y += yIncr;
                            p += pru;
                            oy = y;
                        }
                        else
                        {
                            y += yIncr;
                            p += pr;
                        }
                    }
                    dots.Add(x2, y2, _s, oy - y2 + ad);
                }
                else
                {
                    while (dy > 0)
                    {
                        --dy;
                        y += yIncr;
                        if (p > 0)
                        {
                            dots.Add(x++, oy, _s, y - oy + ad);
                            p += pru;
                            oy = y;
                        }
                        else
                        {
                            p += pr;
                        }
                    }
                    dots.Add(x2, oy, _s, y2 - oy + ad + 1);
                }
            }
            return dots.ToArray();
        }
        public static int[][] LineDott(int x1, int y1, int x2, int y2)
        {
            var dots = new Dots();
            if (x1 > x2)
            {
                var _x2 = x2;
                var _y2 = y2;
                x2 = x1;
                y2 = y1;
                x1 = _x2;
                y1 = _y2;
            }
            var dx = x2 - x1;
            var dy = Math.Abs(y2 - y1);
            var x = x1;
            var y = y1;
            var yIncr = (y1 > y2) ? -1 : 1;
            var drw = true;
            if (dx >= dy)
            {
                var pr = dy << 1;
                var pru = pr - (dx << 1);
                var p = pr - dx;
                while (dx > 0)
                {
                    --dx;
                    if (drw)
                    {
                        dots.Add(x, y, 1, 1);
                    }
                    drw = !drw;
                    if (p > 0)
                    {
                        y += yIncr;
                        p += pru;
                    }
                    else
                    {
                        p += pr;
                    }
                    ++x;
                }
            }
            else
            {
                var pr = dx << 1;
                var pru = pr - (dy << 1);
                var p = pr - dy;
                while (dy > 0)
                {
                    --dy;
                    if (drw)
                    {
                        dots.Add(x, y, 1, 1);
                    }
                    drw = !drw;
                    y += yIncr;
                    if (p > 0)
                    {
                        ++x;
                        p += pru;
                    }
                    else
                    {
                        p += pr;
                    }
                }
            }
            if (drw)
            {
                dots.Add(x, y, 1, 1);
            }
            return dots.ToArray();
        }

        public static int[][] Ellipse(int left, int top, int width, int height)
        {
            var dots = new Dots();
            var a = (++width) >> 1;
            var b = (++height) >> 1;
            var wod = width & 1;
            var hod = height & 1;
            var cx = left + a;
            var cy = top + b;
            var x = 0;
            var y = b;
            var ox = 0;
            var oy = b;
            var aa2 = (a * a) << 1;
            var aa4 = aa2 << 1;
            var bb2 = (b * b) << 1;
            var bb4 = bb2 << 1;
            var st = (aa2 >> 1) * (1 - (b << 1)) + bb2;
            var tt = (bb2 >> 1) - aa2 * ((b << 1) - 1);
            var w = 0;
            var h = 0;
            while (y > 0)
            {
                if (st < 0)
                {
                    st += bb2 * ((x << 1) + 3);
                    tt += bb4 * (++x);
                }
                else if (tt < 0)
                {
                    st += bb2 * ((x << 1) + 3) - aa4 * (y - 1);
                    tt += bb4 * (++x) - aa2 * (((y--) << 1) - 3);
                    w = x - ox;
                    h = oy - y;
                    if ((w & 2) > 0 && (h & 2) > 0)
                    {
                        MakeOvQds(dots, cx, cy, x - 2, y + 2, 1, 1, wod, hod);
                        MakeOvQds(dots, cx, cy, x - 1, y + 1, 1, 1, wod, hod);
                    }
                    else
                    {
                        MakeOvQds(dots, cx, cy, x - 1, oy, w, h, wod, hod);
                    }
                    ox = x;
                    oy = y;
                }
                else
                {
                    tt -= aa2 * ((y << 1) - 3);
                    st -= aa4 * (--y);
                }
            }
            w = a - ox + 1;
            h = (oy << 1) + hod;
            y = cy - oy;
            dots.Add(cx - a, y, w, h);
            dots.Add(cx + ox + wod - 1, y, w, h);
            return dots.ToArray();
        }
        public static int[][] Ellipse2D(int left, int top, int width, int height, int stroke)
        {
            var dots = new Dots();
            var s = stroke;
            width += s + 1;
            height += s + 1;
            var a = width >> 1;
            var b = height >> 1;
            var wod = width & 1;
            var hod = height & 1;
            var cx = left + a;
            var cy = top + b;
            var x = 0;
            var y = b;
            var aa2 = (a * a) << 1;
            var aa4 = aa2 << 1;
            var bb2 = (b * b) << 1;
            var bb4 = bb2 << 1;
            var st = (aa2 >> 1) * (1 - (b << 1)) + bb2;
            var tt = (bb2 >> 1) - aa2 * ((b << 1) - 1);

            if (s - 4 < 0 && (!(s - 2 == 0) || width - 51 > 0 && height - 51 > 0))
            {
                var ox = 0;
                var oy = b;
                var w = 0;
                var h = 0;
                var pxw = 0;
                while (y > 0)
                {
                    if (st < 0)
                    {
                        st += bb2 * ((x << 1) + 3);
                        tt += bb4 * (++x);
                    }
                    else if (tt < 0)
                    {
                        st += bb2 * ((x << 1) + 3) - aa4 * (y - 1);
                        tt += bb4 * (++x) - aa2 * (((y--) << 1) - 3);
                        w = x - ox;
                        h = oy - y;

                        if (w - 1 != 0)
                        {
                            pxw = w + 1 + (s & 1);
                            h = s;
                        }
                        else if (h - 1 != 0)
                        {
                            pxw = s;
                            h += 1 + (s & 1);
                        }
                        else
                        {
                            pxw = h = s;
                        }
                        MakeOvQds(dots, cx, cy, x - 1, oy, pxw, h, wod, hod);
                        ox = x;
                        oy = y;
                    }
                    else
                    {
                        tt -= aa2 * ((y << 1) - 3);
                        st -= aa4 * (--y);
                    }
                }
                dots.Add(cx - a, cy - oy, s, (oy << 1) + hod);
                dots.Add(cx + a + wod - s, cy - oy, s, (oy << 1) + hod);
            }
            else
            {
                var _a = (width - (s << 1)) >> 1;
                var _b = (height - (s << 1)) >> 1;
                var _x = 0;
                var _y = _b;
                var _aa2 = (_a * _a) << 1;
                var _aa4 = _aa2 << 1;
                var _bb2 = (_b * _b) << 1;
                var _bb4 = _bb2 << 1;
                var _st = (_aa2 >> 1) * (1 - (_b << 1)) + _bb2;
                var _tt = (_bb2 >> 1) - _aa2 * ((_b << 1) - 1);

                var pxl = new Dictionary<int, int>();
                var pxt = new Dictionary<int, int>();
                var _pxb = new Dictionary<int, int>();
                pxl.Add(0, 0);
                pxt.Add(0, b);
                _pxb.Add(0, _b - 1);
                while (y > 0)
                {
                    if (st < 0)
                    {
                        pxl.Add(pxl.Count, x);
                        pxt.Add(pxt.Count, y);
                        st += bb2 * ((x << 1) + 3);
                        tt += bb4 * (++x);
                    }
                    else if (tt < 0)
                    {
                        pxl.Add(pxl.Count, x);
                        st += bb2 * ((x << 1) + 3) - aa4 * (y - 1);
                        tt += bb4 * (++x) - aa2 * (((y--) << 1) - 3);
                        pxt.Add(pxt.Count, y);
                    }
                    else
                    {
                        tt -= aa2 * ((y << 1) - 3);
                        st -= aa4 * (--y);
                    }

                    if (_y > 0)
                    {
                        if (_st < 0)
                        {
                            _st += _bb2 * ((_x << 1) + 3);
                            _tt += _bb4 * (++_x);
                            _pxb.Add(_pxb.Count, _y - 1);
                        }
                        else if (_tt < 0)
                        {
                            _st += _bb2 * ((_x << 1) + 3) - _aa4 * (_y - 1);
                            _tt += _bb4 * (++_x) - _aa2 * (((_y--) << 1) - 3);
                            _pxb.Add(_pxb.Count, _y - 1);
                        }
                        else
                        {
                            _tt -= _aa2 * ((_y << 1) - 3);
                            _st -= _aa4 * (--_y);
                            _pxb[_pxb.Count - 1]--;
                        }
                    }
                }

                var ox = -wod;
                var oy = b;
                var _oy = _pxb[0];
                var l = pxl.Count;
                for (var i = 0; i < l; i++)
                {
                    if (_pxb.ContainsKey(i))
                    {
                        if (_pxb[i] < _oy || pxt[i] < oy)
                        {
                            x = pxl[i];
                            MakeOvQds(dots, cx, cy, x, oy, x - ox, oy - _oy, wod, hod);
                            ox = x;
                            oy = pxt[i];
                            _oy = _pxb[i];
                        }
                    }
                    else
                    {
                        x = pxl[i];
                        dots.Add(cx - x, cy - oy, 1, (oy << 1) + hod);
                        dots.Add(cx + ox + wod, cy - oy, 1, (oy << 1) + hod);
                        ox = x;
                        oy = pxt[i];
                    }
                }
                dots.Add(cx - a, cy - oy, 1, (oy << 1) + hod);
                dots.Add(cx + ox + wod, cy - oy, 1, (oy << 1) + hod);
            }
            return dots.ToArray();
        }
        public static int[][] EllipseDott(int left, int top, int width, int height)
        {
            var dots = new Dots();
            var a = (++width) >> 1;
            var b = (++height) >> 1;
            var wod = width & 1;
            var hod = height & 1;
            var hodu = hod ^ 1;
            var cx = left + a;
            var cy = top + b;
            var x = 0;
            var y = b;
            var aa2 = (a * a) << 1;
            var aa4 = aa2 << 1;
            var bb2 = (b * b) << 1;
            var bb4 = bb2 << 1;
            var st = (aa2 >> 1) * (1 - (b << 1)) + bb2;
            var tt = (bb2 >> 1) - aa2 * ((b << 1) - 1);
            var drw = true;
            while (y > 0)
            {
                if (st < 0)
                {
                    st += bb2 * ((x << 1) + 3);
                    tt += bb4 * (++x);
                }
                else if (tt < 0)
                {
                    st += bb2 * ((x << 1) + 3) - aa4 * (y - 1);
                    tt += bb4 * (++x) - aa2 * (((y--) << 1) - 3);
                }
                else
                {
                    tt -= aa2 * ((y << 1) - 3);
                    st -= aa4 * (--y);
                }
                if (drw && y >= hodu)
                {
                    MakeOvQds(dots, cx, cy, x, y, 1, 1, wod, hod);
                }
                drw = !drw;
            }
            return dots.ToArray();
        }
        public static int[][] FillEllipse(int left, int top, int width, int height)
        {
            var dots = new Dots();
            var a = width >> 1;
            var b = height >> 1;
            var wod = width & 1;
            var hod = height & 1;
            var cx = left + a;
            var cy = top + b;
            var x = 0;
            var y = b;
            var oy = b;
            var aa2 = (a * a) << 1;
            var aa4 = aa2 << 1;
            var bb2 = (b * b) << 1;
            var bb4 = bb2 << 1;
            var st = (aa2 >> 1) * (1 - (b << 1)) + bb2;
            var tt = (bb2 >> 1) - aa2 * ((b << 1) - 1);
            var xl = 0;
            var dw = 0;
            var dh = 0;
            if (width > 0)
            {
                while (y > 0)
                {
                    if (st < 0)
                    {
                        st += bb2 * ((x << 1) + 3);
                        tt += bb4 * (++x);
                    }
                    else if (tt < 0)
                    {
                        st += bb2 * ((x << 1) + 3) - aa4 * (y - 1);
                        xl = cx - x;
                        dw = (x << 1) + wod;
                        tt += bb4 * (++x) - aa2 * (((y--) << 1) - 3);
                        dh = oy - y;
                        dots.Add(xl, cy - oy, dw, dh);
                        dots.Add(xl, cy + y + hod, dw, dh);
                        oy = y;
                    }
                    else
                    {
                        tt -= aa2 * ((y << 1) - 3);
                        st -= aa4 * (--y);
                    }
                }
            }
            dots.Add(cx - a, cy - oy, width, (oy << 1) + hod);
            return dots.ToArray();
        }

        public static int[][] Rect(int x, int y, int w, int h, int stroke)
        {
            var dots = new Dots();
            var s = stroke;
            dots.Add(x, y, w, s);
            dots.Add(x + w, y, s, h);
            dots.Add(x, y + h, w + s, s, true);
            dots.Add(x, y + s, s, h - s, true);
            return dots.ToArray();
        }
        public static int[][] RectDott(int x, int y, int w, int h)
        {
            var dots = new Dots();
            dots.AddRange(LineDott(x, y, x + w, y));
            dots.AddRange(LineDott(x + w, y, x + w, y + h));
            dots.AddRange(LineDott(x, y + h, x + w, y + h));
            dots.AddRange(LineDott(x, y, x, y + h));
            return dots.ToArray();
        }
        public static int[][] FillRect(int x, int y, int w, int h)
        {
            var dots = new Dots();
            dots.Add(x, y, w, h);
            return dots.ToArray();
        }

        public static int[][] Arc(int iL, int iT, int iW, int iH, double fAngA, double fAngZ)
        {
            var dots = new Dots();
            var a = iW >> 1;
            var b = iH >> 1;
            var iOdds = (iW & 1) | ((iH & 1) << 16);
            var cx = iL + a;
            var cy = iT + b;
            var x = 0;
            var y = b;
            var ox = x;
            var oy = y;
            var aa2 = (a * a) << 1;
            var aa4 = aa2 << 1;
            var bb2 = (b * b) << 1;
            var bb4 = bb2 << 1;
            var st = (aa2 >> 1) * (1 - (b << 1)) + bb2;
            var tt = (bb2 >> 1) - aa2 * ((b << 1) - 1);
            // Vars for radial boundary lines
            var xEndA = 0;
            var yEndA = 0;
            var xEndZ = 0;
            var yEndZ = 0;
            var iSects = (1 << ((int)Math.Floor((fAngA %= 360) / 180d) << 3)) |
                (2 << ((int)Math.Floor((fAngZ %= 360) / 180d) << 3)) |
                ((fAngA >= fAngZ ? 1 : 0) << 16);
            var aBndA = new int[b + 1];
            var aBndZ = new int[b + 1];

            // Set up radial boundary lines
            fAngA *= Math.PI / 180;
            fAngZ *= Math.PI / 180;

            xEndA = (int)(cx + Math.Round(a * Math.Cos(fAngA)));
            yEndA = (int)(cy + Math.Round(-b * Math.Sin(fAngA)));
            MakeLinVirt(aBndA, cx, cy, xEndA, yEndA);
            xEndZ = (int)(cx + Math.Round(a * Math.Cos(fAngZ)));
            yEndZ = (int)(cy + Math.Round(-b * Math.Sin(fAngZ)));
            MakeLinVirt(aBndZ, cx, cy, xEndZ, yEndZ);

            while (y > 0)
            {
                if (st < 0) // Advance x
                {
                    st += bb2 * ((x << 1) + 3);
                    tt += bb4 * (++x);
                }
                else if (tt < 0) // Advance x and y
                {
                    st += bb2 * ((x << 1) + 3) - aa4 * (y - 1);
                    ox = x;
                    tt += bb4 * (++x) - aa2 * (((y--) << 1) - 3);
                    MakeArcDots(dots, ox, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
                    oy = y;
                }
                else // Advance y
                {
                    tt -= aa2 * ((y << 1) - 3);
                    st -= aa4 * (--y);
                    if (y != 0 && (aBndA[y] != aBndA[y - 1] || aBndZ[y] != aBndZ[y - 1]))
                    {
                        MakeArcDots(dots, x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
                        ox = x;
                        oy = y;
                    }
                }
            }
            MakeArcDots(dots, x, 0, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
            if ((iOdds >> 16) != 0) // Odd height
            {
                if ((iSects >> 16) != 0) // Start-angle > end-angle
                {
                    var xl = (yEndA <= cy || yEndZ > cy) ? (cx - x) : cx;
                    dots.Add(xl, cy, x + cx - xl + (iOdds & 0xffff), 1);
                }
                else if ((iSects & 0x01) != 0 && yEndZ > cy)
                {
                    dots.Add(cx - x, cy, x, 1);
                }
            }
            return dots.ToArray();
        }
    }
}
